import os
import re
import pandas as pd
import docx
import concurrent.futures
import logging
from tqdm import tqdm
import win32com.client
import pythoncom
import tempfile
import argparse
import sys

# 配置日志
def setup_logging(log_file="word_parser.log"):
    logging.basicConfig(
        level=logging.DEBUG,  # 修改为DEBUG级别以获取更多信息
        format='%(asctime)s - %(levelname)s - %(message)s',
        handlers=[
            logging.FileHandler(log_file, encoding='utf-8'),
            logging.StreamHandler()
        ]
    )

# 定义要提取的字段
FIELDS = [
    "应用名称", "应用包名", "开发者", "版本信息", "应用商城", 
    "检测结果", "问题类型", "问题描述", "备注"
]

def convert_doc_to_docx(doc_path):
    """将.doc格式转换为.docx格式"""
    word = None
    try:
        # 初始化COM组件
        pythoncom.CoInitialize()
        word = win32com.client.Dispatch("Word.Application")
        word.Visible = False
        
        # 创建临时文件路径
        temp_dir = tempfile.gettempdir()
        docx_path = os.path.join(temp_dir, os.path.basename(doc_path) + "x")
        
        # 打开文档
        doc = word.Documents.Open(doc_path)
        
        # 保存为.docx
        doc.SaveAs2(docx_path, FileFormat=16)  # 16代表.docx格式
        
        # 关闭文档
        doc.Close()
        
        return docx_path
    except Exception as e:
        logging.error(f"转换文档 {doc_path} 时出错: {str(e)}")
        return None
    finally:
        # 确保Word应用被关闭
        try:
            if word:
                word.Quit()
        except:
            pass
        # 释放COM组件
        pythoncom.CoUninitialize()

def find_section_paragraphs(doc, section_title, section_number=None):
    """找到指定章节的所有段落
    
    Args:
        doc: Word文档对象
        section_title: 章节标题
        section_number: 章节编号，如果指定则精确匹配编号
    """
    section_paragraphs = []
    found_section = False
    next_section_pattern = re.compile(r"^\d+\.\s")
    
    # 记录所有段落标题，帮助调试
    all_headings = []
    
    for i, para in enumerate(doc.paragraphs):
        text = para.text.strip()
        if text and (text.startswith(str(i+1)) or re.match(r"^\d+\.", text)):
            all_headings.append(text)
        
        # 查找章节标题 - 更宽松的匹配
        if section_title in text:
            # 如果指定了章节编号，则需要精确匹配
            if section_number is not None:
                if text.startswith(f"{section_number}.") or text.startswith(f"{section_number} "):
                    found_section = True
                    logging.debug(f"找到章节 '{section_title}' (编号 {section_number}) 在段落 {i}: {text}")
                    continue
            else:
                found_section = True
                logging.debug(f"找到章节 '{section_title}' 在段落 {i}: {text}")
                continue
        
        # 如果找到章节，收集段落直到下一个章节
        if found_section:
            # 如果遇到下一个章节标题，则结束收集
            if next_section_pattern.match(text) and section_title not in text:
                logging.debug(f"在段落 {i} 处结束章节: {text}")
                break
            
            if text:  # 只添加非空段落
                section_paragraphs.append(para)
    
    if not found_section:
        logging.debug(f"未找到章节 '{section_title}'{' 编号 ' + str(section_number) if section_number is not None else ''}，文档中的标题有: {all_headings}")
    else:
        logging.debug(f"章节 '{section_title}' 中找到 {len(section_paragraphs)} 个段落")
    
    return section_paragraphs

def extract_app_info_from_table(doc):
    """从表格中提取应用基本信息"""
    app_info = {field: "" for field in FIELDS[:5]}
    
    # 遍历所有表格
    for table in doc.tables:
        # 检查表格行数
        if len(table.rows) < 2:
            continue
            
        # 遍历表格行
        for row in table.rows:
            # 确保行至少有两个单元格
            if len(row.cells) < 2:
                continue
                
            # 获取第一个单元格的文本（可能是字段名）
            field_cell = row.cells[0].text.strip()
            # 获取第二个单元格的文本（可能是字段值）
            value_cell = row.cells[1].text.strip()
            
            # 匹配字段
            if "应用名称" in field_cell and not app_info["应用名称"]:
                app_info["应用名称"] = value_cell
                logging.debug(f"从表格中提取到应用名称: {value_cell}")
            elif "应用包名" in field_cell and not app_info["应用包名"]:
                app_info["应用包名"] = value_cell
                logging.debug(f"从表格中提取到应用包名: {value_cell}")
            elif "开发者" in field_cell and not app_info["开发者"]:
                app_info["开发者"] = value_cell
                logging.debug(f"从表格中提取到开发者: {value_cell}")
            elif "版本" in field_cell and not app_info["版本信息"]:
                app_info["版本信息"] = value_cell
                logging.debug(f"从表格中提取到版本信息: {value_cell}")
            elif "应用商城" in field_cell and not app_info["应用商城"]:
                app_info["应用商城"] = value_cell
                logging.debug(f"从表格中提取到应用商城: {value_cell}")
    
    return app_info

def extract_app_info(doc):
    """提取应用基本信息"""
    # 首先尝试从表格中提取信息
    app_info = extract_app_info_from_table(doc)
    
    # 如果表格中没有足够信息，再尝试从段落中提取
    if not all(app_info.values()):
        logging.debug("表格中未找到完整信息，尝试从段落中提取")
        
        # 获取应用基本信息章节的段落
        app_info_paragraphs = find_section_paragraphs(doc, "应用基本信息")
        
        # 记录找到的段落数量
        logging.debug(f"应用基本信息章节找到 {len(app_info_paragraphs)} 个段落")
        
        # 定义正则表达式模式，用于提取信息
        patterns = {
            "应用名称": r"应用名称[：:]\s*(.*)",
            "应用包名": r"(?:应用包名|包名)[：:]\s*(.*)",
            "开发者": r"(?:开发者|开发商)[：:]\s*(.*)",
            "版本信息": r"版本[信息]?[：:]?\s*([\d\.]+|V\d+\.[\d\.]+)",  # 改进版本信息匹配模式
            "应用商城": r"(?:应用商城|应用市场)[：:]\s*(.*)"
        }
        
        # 遍历段落提取信息
        all_text = "\n".join([p.text for p in app_info_paragraphs])
        logging.debug(f"应用基本信息章节文本: {all_text}")
        
        # 首先尝试从整个文本中提取
        for field, pattern in patterns.items():
            if not app_info[field]:  # 如果字段还没有值
                match = re.search(pattern, all_text)
                if match:
                    app_info[field] = match.group(1).strip()
                    logging.debug(f"从整个文本中提取到 {field}: {app_info[field]}")
        
        # 如果某些字段没有提取到，尝试逐段落提取
        for para in app_info_paragraphs:
            text = para.text.strip()
            for field, pattern in patterns.items():
                if not app_info[field]:  # 如果字段还没有值
                    match = re.search(pattern, text)
                    if match:
                        app_info[field] = match.group(1).strip()
                        logging.debug(f"从段落中提取到 {field}: {app_info[field]}")
        
        # 如果应用基本信息章节没有找到或者没有提取到足够信息，尝试从整个文档中提取
        if not app_info_paragraphs or not all(app_info.values()):
            logging.debug("从整个文档中尝试提取信息")
            # 尝试更宽松的匹配模式
            broader_patterns = {
                "应用名称": r"(?:应用名称|软件名称|名称)[：:]\s*([^\n\r]+)",
                "应用包名": r"(?:应用包名|包名|应用标识|APP ID)[：:]\s*([^\n\r]+)",
                "开发者": r"(?:开发者|开发商|研发商|发行商)[：:]\s*([^\n\r]+)",
                "版本信息": r"(?:版本[信息]?|版本号)[：:]\s*([^\n\r]+)",
                "应用商城": r"(?:应用商城|应用市场|分发渠道)[：:]\s*([^\n\r]+)"
            }
            
            # 从所有段落中查找
            for para in doc.paragraphs:
                text = para.text.strip()
                if text:
                    for field, pattern in broader_patterns.items():
                        if not app_info[field]:  # 如果字段还没有值
                            match = re.search(pattern, text)
                            if match:
                                app_info[field] = match.group(1).strip()
                                logging.debug(f"从全文段落中提取到 {field}: {app_info[field]}")
    
    # 特殊处理版本信息
    if not app_info["版本信息"]:
        # 尝试更宽松的版本匹配
        version_patterns = [
            r"版本[号码]?[：:]\s*(.+?)(?:\s|$)",
            r"版本[：:]\s*(.+?)(?:\s|$)",
            r"版本[号]?[是为]\s*(.+?)(?:\s|$)",
            r"V(\d+\.[\d\.]+)",
            r"v(\d+\.[\d\.]+)",
            r"(\d+\.\d+\.\d+)",
            r"(\d+\.\d+)"
        ]
        
        for pattern in version_patterns:
            for para in doc.paragraphs:
                text = para.text.strip()
                match = re.search(pattern, text)
                if match:
                    app_info["版本信息"] = match.group(1).strip()
                    logging.debug(f"从特殊版本匹配中提取到版本信息: {app_info['版本信息']}")
                    break
            if app_info["版本信息"]:
                break
    
    return app_info

def check_user_rights_violation(doc):
    """检查侵害用户权益章节，并提取问题类型和描述"""
    result = {
        "检测结果": "通过",
        "问题类型": "",
        "问题描述": "",
        "备注": ""
    }
    
    # 尝试找到"（三）侵害用户权益问题："章节
    violation_paragraphs = []
    found_section = False
    
    for i, para in enumerate(doc.paragraphs):
        text = para.text.strip()
        
        # 查找"（三）侵害用户权益问题："章节
        if ("（三）" in text and "侵害用户权益问题" in text) or \
           ("(三)" in text and "侵害用户权益问题" in text) or \
           (text.startswith("三") and "侵害用户权益问题" in text):
            found_section = True
            logging.debug(f"找到侵害用户权益问题章节: {text}")
            continue
        
        # 如果找到章节，收集段落直到下一个章节
        if found_section:
            # 如果遇到下一个章节标题（通常以数字开头），则结束收集
            if re.match(r"^[（\(]?[四五六七八九十]", text) or re.match(r"^\d+\.", text):
                logging.debug(f"在段落处结束侵害用户权益问题章节: {text}")
                break
            
            if text:  # 只添加非空段落
                violation_paragraphs.append(text)
    
    # 合并所有段落内容
    all_content = "\n".join(violation_paragraphs)
    logging.debug(f"侵害用户权益问题章节内容: {all_content}")
    
    # 检查内容是否为"无"或类似表示
    if not all_content or all_content.strip().lower() in ["无"]:
        result["检测结果"] = "通过"
        result["问题描述"] = "无"
        logging.debug("侵害用户权益问题为'无'，检测结果为'通过'")
    else:
        result["检测结果"] = "未通过"
        result["问题描述"] = all_content
    return result

def process_document(file_path):
    """处理单个Word文档"""
    try:
        # 检查文件是否存在
        if not os.path.exists(file_path):
            logging.error(f"文件不存在: {file_path}")
            return {field: "" for field in FIELDS}
        
        logging.info(f"开始处理文件: {file_path}")
            
        # 检查文件类型
        temp_file = None
        if file_path.endswith('.doc'):
            # 如果是.doc格式，先转换为.docx
            temp_file = convert_doc_to_docx(file_path)
            if not temp_file:
                logging.error(f"无法转换文件 {file_path}")
                return {field: "" for field in FIELDS}
            doc_path = temp_file
        else:
            doc_path = file_path
        
        # 打开文档
        doc = docx.Document(doc_path)
        
        # 记录文档基本信息
        logging.debug(f"文档有 {len(doc.paragraphs)} 个段落, {len(doc.tables)} 个表格")
        
        # 尝试从文件名提取应用名称
        file_name = os.path.basename(file_path)
        app_name_from_file = ""
        # 尝试提取括号前的应用名称
        if "(" in file_name:
            app_name_from_file = file_name.split("(")[0].strip()
            logging.debug(f"从文件名提取到应用名称: {app_name_from_file}")
        
        # 提取应用基本信息
        app_info = extract_app_info(doc)
        
        # 如果应用名称为空，使用文件名中提取的应用名称
        if not app_info["应用名称"] and app_name_from_file:
            app_info["应用名称"] = app_name_from_file
        
        # 检查侵害用户权益章节
        rights_violation_info = check_user_rights_violation(doc)
        
        # 合并信息
        result = {**app_info, **rights_violation_info}
        
        # 清理临时文件
        if temp_file and os.path.exists(temp_file):
            try:
                os.remove(temp_file)
            except:
                pass
        
        logging.info(f"成功解析文件: {os.path.basename(file_path)}")
        logging.debug(f"解析结果: {result}")
        return result
    
    except Exception as e:
        logging.error(f"处理文件 {file_path} 时出错: {str(e)}")
        import traceback
        logging.error(traceback.format_exc())
        # 返回空结果
        return {field: "" for field in FIELDS}

def process_documents(directory, max_workers=10):
    """多线程处理目录下的所有Word文档"""
    if not os.path.exists(directory):
        logging.error(f"目录不存在: {directory}")
        return []
    
    # 获取所有Word文档
    doc_files = [os.path.join(directory, f) for f in os.listdir(directory) 
                if f.endswith('.doc') or f.endswith('.docx')]
    
    if not doc_files:
        logging.warning(f"在目录 {directory} 中未找到Word文档")
        return []
    
    logging.info(f"找到 {len(doc_files)} 个Word文档")
    results = []
    
    # 使用线程池处理文档
    max_workers = min(max_workers, len(doc_files))
    logging.info(f"使用 {max_workers} 个线程进行处理")
    
    with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
        # 提交所有任务并显示进度条
        future_to_file = {executor.submit(process_document, file_path): file_path for file_path in doc_files}
        
        for future in tqdm(concurrent.futures.as_completed(future_to_file), total=len(doc_files), desc="处理文档"):
            file_path = future_to_file[future]
            try:
                result = future.result()
                if result:
                    results.append(result)
            except Exception as e:
                logging.error(f"获取 {file_path} 的处理结果时出错: {str(e)}")
    
    return results

def parse_arguments():
    """解析命令行参数"""
    parser = argparse.ArgumentParser(description='解析Word文档并提取应用信息')
    parser.add_argument('-i', '--input', type=str, default=r"F:\20250716\report",
                        help='包含Word文档的目录路径')
    parser.add_argument('-o', '--output', type=str, default=r"F:\20250716\report_analysis.xlsx",
                        help='输出Excel文件路径')
    parser.add_argument('-t', '--threads', type=int, default=10,
                        help='处理文档的线程数')
    parser.add_argument('-l', '--log', type=str, default="word_parser.log",
                        help='日志文件路径')
    
    return parser.parse_args()

def main():
    """主函数"""
    # 解析命令行参数
    args = parse_arguments()
    
    # 设置日志
    setup_logging(args.log)
    
    logging.info(f"开始处理目录: {args.input}")
    logging.info(f"输出文件: {args.output}")
    logging.info(f"使用线程数: {args.threads}")
    
    try:
        # 处理文档
        results = process_documents(args.input, args.threads)
        
        if not results:
            logging.error("未能成功解析任何文档")
            return 1
        
        # 创建DataFrame并保存为Excel
        df = pd.DataFrame(results)
        
        # 确保所有列都存在
        for field in FIELDS:
            if field not in df.columns:
                df[field] = ""
        
        # 重新排序列
        df = df[FIELDS]
        
        # 确保输出目录存在
        output_dir = os.path.dirname(args.output)
        if output_dir and not os.path.exists(output_dir):
            os.makedirs(output_dir)
        
        # 保存到Excel
        df.to_excel(args.output, index=False)
        logging.info(f"解析完成，结果已保存到: {args.output}")
        logging.info(f"共处理 {len(results)} 个文档")
        return 0
    
    except Exception as e:
        logging.error(f"处理过程中出错: {str(e)}")
        return 1

if __name__ == "__main__":
    sys.exit(main()) 